<?php

namespace plugin\admin\app\traits;

use app\service\modbus\ModbusTcpService;
use plugin\admin\app\model\IotCollectDatum;
use plugin\admin\app\model\IotCollectDetail;
use plugin\admin\app\model\IotSignal;
use support\Response;
use Workerman\Crontab\Crontab;
use Workerman\Mqtt\Client;

trait IotCollectTask
{
    /**
     * 执行计划任务
     * @return Response
     */
    public function working(): Response
    {
        $task_id = request()->post('id','');
        if (empty($task_id)){
            return errorMessage("参数错误");
        }
        $data_task = $this->model->find($task_id);
        if (empty($data_task)){
            return errorMessage("数据错误");
        }
        $iot_collect_detail_data = IotCollectDetail::with(['get_device','get_child_device','get_point_group'])->where(['storage_action'=>'STORE:MYSQL'])->where("collect_task_id",$task_id)->get();
        if (empty($iot_collect_detail_data->toArray())){
            $this->model->where('id',$task_id)->update(['status'=>'stop']);
            return errorMessage("未配置采集任务配置或者相关协议未开发");
        }
        $status = $data_task->status;
        if ($status=="stop"){
            $this->model->where('id',$task_id)->update(['status'=>'start']);
        }else{
            $this->model->where('id',$task_id)->update(['status'=>'stop']);
        }
        return successMessage();

        //todo 如果需要点击一下就运行一次,那就要先停掉定时任务. 修改代码后不会执行该方法, 获取的值还要根据主题实际返回的值进行修改
        $cron = $data_task->cron;
        $iot_collect_detail_data = IotCollectDetail::with(['get_device','get_child_device','get_point_group'])->where(['storage_action'=>'STORE:MYSQL'])->where("collect_task_id",$task_id)->get();
        if (empty($iot_collect_detail_data->toArray())){
            $this->model->where('id',$task_id)->update(['status'=>'stop']);
            return errorMessage("未配置采集任务配置或者相关协议未开发");
        }
        //,'collect_action'=>'CLIENT:MODBUS:TCP'
        // 每秒钟执行一次
        $destroy = new Crontab($cron, function()use($task_id,$iot_collect_detail_data,&$destroy){
            $error ='';
            foreach ($iot_collect_detail_data as $value){
                $date = date("Y-m-d H:i:s");
                $collect_action = $value->collect_action;
                $lecp_server_name = ($value->get_device)['lecp_server_name'];
                $is_lecp_server =($value->get_device)['is_lecp_server'];
                $device_name =($value->get_device)['name'];
                $device_id = $value->device_id;
                $host = ($value->get_device)['ip'];
                $port = ($value->get_device)['port'];
                $signal_json = ($value->get_point_group)['signal_json'];
                if(strstr($collect_action, 'PLC:')){
                    $uri = "http://{$host}:{$port}";
                    if ($signal_json){
                        $signal_json_data = explode(',',$signal_json);
                        $signal_data = IotSignal::whereIn('id',$signal_json_data)->where('type',1)->select(['id','name','address','type','field_name','field_type'])->get();
                        if ($signal_data){
                            $action = "plc_read_node";
                            $date = date("Y-m-d H:i:s");
                            foreach ($signal_data as $_v){
                                $address = $_v->address;
                                $field_type = $_v->field_type;
                                if ($is_lecp_server==1 && $lecp_server_name){
                                    $node="NODES.{$lecp_server_name}.{$address}";
                                    $data = json_encode(['action'=>$action,'node'=>$node]);
                                    $rtval = http_post($uri,$data);
                                    if ($rtval){
                                        if ($rtval['errcode']==0){
                                            //获取数据成功
                                            $value = $rtval['rtval'][0];
                                            $add['device_id']=$device_id;
                                            $add['child_device_id']=0;
                                            $add['address']=$address;
                                            $add['field_type']=$field_type;
                                            $add['signal_id']=$_v->id;
                                            $add['collect_task_id']=$task_id;
                                            $add['status']=1;
                                            $add['value']=$value;
                                            $add['collect_time']=$date;
                                            $add['create_time']=$date;
                                            $add['reason']="数据抓取正常:LECPServer正常";
                                            IotCollectDatum::insert($add);
                                        }
                                    }else{
                                        //获取数据成功
                                        $add['device_id']=$device_id;
                                        $add['child_device_id']=0;
                                        $add['address']=$address;
                                        $add['field_type']=-1;
                                        $add['signal_id']=$_v->id;
                                        $add['collect_task_id']=$task_id;
                                        $add['status']=0;
                                        $add['value']=0;
                                        $add['collect_time']=$date;
                                        $add['create_time']=$date;
                                        $add['reason'] ="数据抓异常:LECPServer未启动或数据错误";
                                        IotCollectDatum::insert($add);
                                        $destroy->destroy();
                                        $this->model->where('id',$task_id)->update(['status'=>'stop']);
                                        return true;
                                    }
                                }
                            }
                        }
                    }
                }elseif(strstr($collect_action,"CLIENT:MODBUS:")){
                    $uri = "tcp://{$host}:{$port}";
                    $collect_detail_id = $value->child_device_id;
                    $modbus_service_list = new ModbusTcpService();
                    //判断设备是否在线
                    $modbus_service = new ModbusTcpService($host,$port);
                    $isOnline = $modbus_service->isOnline();
                    if ($isOnline=="online"){
                        //在线进行数据获取 点位地址
                        if ($signal_json){
                            $signal_json_data = explode(',',$signal_json);
                            $signal_data = IotSignal::whereIn('id',$signal_json_data)->where('type',1)->select(['id','name','address','type','field_name','field_type','field_bit_address'])->get();
                            if ($signal_data){
                                foreach ($signal_data as $_k=>$_value){
                                    $field_type = $_value->field_type;
                                    $field_type_name = "string";
                                    if($field_type==0){
                                        $field_type_name="bit";
                                    }elseif ($field_type==1){
                                        $field_type_name="int16";
                                    }elseif ($field_type==2){
                                        $field_type_name="uint16";
                                    }elseif ($field_type==3){
                                        $field_type_name="int32";
                                    }elseif ($field_type==4){
                                        $field_type_name="uint32";
                                    }elseif ($field_type==5){
                                        $field_type_name="uint64";
                                    }elseif ($field_type==6){
                                        $field_type_name="float";
                                    }elseif ($field_type==8){
                                        $field_type_name="double";
                                    }elseif ($field_type==9){
                                        $field_type_name="bit";
                                    }elseif ($field_type==10){
                                        $field_type_name="byte";
                                    }elseif ($field_type==11){
                                        $field_type_name="int64";
                                    }
                                    if ($field_type_name=="bit"){
                                        $bit = $value->field_bit_address;
                                        $arr = [
                                            ['uri' => $uri, 'start_address' => $_value->address, 'get_type' => $field_type_name,'bit'=>$bit, 'name' => $_value->field_name]
                                        ];
                                    }else{
                                        $arr = [
                                            ['uri' => $uri, 'start_address' => $_value->address, 'get_type' => $field_type_name, 'name' => $_value->field_name]
                                        ];
                                    }
                                    $field_name = $_value->field_name;
                                    //获取到数据
                                    $date = date("Y-m-d H:i:s");
                                    $get_data = $modbus_service_list->getModbusTcpTypeMultipleRead($arr);
                                    if (is_array($get_data)){
                                        $add['device_id']=$device_id;
                                        $add['child_device_id']=$collect_detail_id;
                                        $add['address']=$_value->address;
                                        $add['field_type']=$field_type;
                                        $add['signal_id']=$_value->id;
                                        $add['collect_task_id']=$task_id;
                                        $add['status']=1;
                                        $add['value']=$get_data[$field_name];
                                        $add['collect_time']=$date;
                                        $add['create_time']=$date;
                                        $add['reason']="数据抓取正常";
                                        IotCollectDatum::insert($add);
                                    }else{
                                        $add['device_id']=$device_id;
                                        $add['child_device_id']=$collect_detail_id;
                                        $add['address']=0;
                                        $add['field_type']=-1;
                                        $add['signal_id']=0;
                                        $add['collect_task_id']=$task_id;
                                        $add['status']=0;
                                        $add['value']=0;
                                        $add['collect_time']=$date;
                                        $add['create_time']=$date;
                                        $add['reason']="数据抓取异常: ".$get_data;
                                        IotCollectDatum::insert($add);
                                        $error = $get_data;
                                    }
                                    if ($error){
                                        break;
                                    }
                                }
                            }
                        }
                    }else{
                        $add['device_id']=$device_id;
                        $add['child_device_id']=$collect_detail_id;
                        $add['address']=0;
                        $add['field_type']=-1;
                        $add['signal_id']=0;
                        $add['collect_task_id']=$task_id;
                        $add['status']=0;
                        $add['value']=0;
                        $add['collect_time']=$date;
                        $add['create_time']=$date;
                        $add['reason']="设备【".$device_name."】未启动,需要核实信息";
                        IotCollectDatum::insert($add);
                        $this->model->where('id',$task_id)->update(['status'=>'stop']);
                        $destroy->destroy();
                        return true;
                    }
                    //设备不在线记录日志
                }elseif($collect_action=="CLIENT:MQTT"){
                    if ($signal_json){
                        $signal_json_data = explode(',',$signal_json);
                        $signal_data = IotSignal::whereIn('id',$signal_json_data)->where('type',3)->select(['id','name','address','type','field_name','field_type'])->get();
                        $options=[];
                        $mqtt = new Client("mqtt://{$host}:{$port}",$options);
                        //获取需要订阅的主题
                        $subscribe=[];
                        foreach ($signal_data as $k=>$v){
                            $id = $device_id;
                            $address = $v->address;
                            $address = str_replace('{$id}',$id, $address);
                            $subscribe[$address]=$k;
                        }
                        if (empty($subscribe)){
                            return errorMessage("mqtt订阅主题未配置");
                        }
                        $mqtt->onConnect = function ($mqtt) use ($subscribe,$device_id) {
                            //订阅主题
                            $mqtt->subscribe($subscribe);
                        };
                        $mqtt->onMessage = function ($topic, $content) use($device_id,$signal_data,$task_id){
                            $topic = str_replace($device_id,'{$id}', $topic);
                            $signal_id= IotSignal::where('address',$topic)->value('id');
                            //获取需要订阅的主题对应的内容
                            $date = date("Y-m-d H:i:s");
                            $exists = IotCollectDatum::where(['address'=>$topic,'value'=>$content,'collect_time'=>$date])->exists();
                            if (empty($exists)){
                                $add['device_id']=$device_id;
                                $add['child_device_id']=0;
                                $add['address']=$topic;
                                $add['field_type']=7;
                                $add['signal_id']=$signal_id;
                                $add['collect_task_id']=$task_id;
                                $add['status']=1;
                                $add['value']=$content;
                                $add['collect_time']=$date;
                                $add['create_time']=$date;
                                $add['reason']="数据抓取正常";
                                IotCollectDatum::insert($add);
                            }
                        };
                        $mqtt->onClose = function ($mqtt) use ($task_id) {
                            $this->model->where('id', $task_id)->update(['status' => "stop"]);
                            $mqtt->close();
                        };
                        $mqtt->connect();
                    }
                }else{
                    return errorMessage("未处理");
                }
            }
            if ($error){
                //$destroy->destroy();
            }
            return true;
        });
        $status = $data_task->status;
        if($status=="start"){
            $destroy->destroy();
            $this->model->where('id',$task_id)->update(['status'=>'stop']);
        }else{
            $this->model->where('id',$task_id)->update(['status'=>'start']);
        }
        return successMessage("成功",[]);
    }
}
